package com.a21vianet.quincysx.demo.binderpool.pool;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import com.a21vianet.quincysx.demo.binderpool.IBinderPool;
import com.a21vianet.quincysx.demo.binderpool.RemoteIBinderPoolService;

import java.util.concurrent.CountDownLatch;

public class BinderPool {
    private static final String TAG = BinderPool.class.getSimpleName();

    public static final int BINDER_NONE = -1;
    public static final int BINDER_COMPUTE = 0;
    public static final int BINDER_SECURITY_CENTER = 1;

    private Context mContext;
    private IBinderPool mIBinderPool;
    private static volatile BinderPool sInstance;
    private CountDownLatch mConnectBinderCountDownLatch;

    private BinderPool(Context context) {
        mContext = context.getApplicationContext();
        connectBinderPoolService();
    }

    public static BinderPool getInstance(Context context) {
        if (sInstance == null) {
            synchronized (BinderPool.class) {
                if (sInstance == null) {
                    sInstance = new BinderPool(context);
                }
            }
        }
        return sInstance;
    }

    /**
     * 请使用子线程来调用，否则 CountDownLatch.await() 将会出现死锁
     */
    private synchronized void connectBinderPoolService() {
        mConnectBinderCountDownLatch = new CountDownLatch(1);
        Log.e("====", "connectBinderPoolService:" + Thread.currentThread().getName());
        Intent intent = new Intent(mContext, RemoteIBinderPoolService.class);
        mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
        try {
            mConnectBinderCountDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public IBinder queryBinder(int binderCode) {
        IBinder binder = null;
        try {
            if (mIBinderPool != null) {
                binder = mIBinderPool.queryBinder(binderCode);
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return binder;
    }

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e("====", "onServiceConnected:" + Thread.currentThread().getName());
            if (service == null) {
                return;
            }
            mIBinderPool = IBinderPool.Stub.asInterface(service);
            mConnectBinderCountDownLatch.countDown();
            try {
                mIBinderPool.asBinder().linkToDeath(mDeathRecipient, 0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    /**
     * 为什么使用这种方式来监听服务异常
     * 因为这个回调方法运行环境是子线程，如果使用主线程调用 connectBinderPoolService 会出现死锁
     */
    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            mIBinderPool.asBinder().unlinkToDeath(mDeathRecipient, 0);
            mIBinderPool = null;
            connectBinderPoolService();
        }
    };
}
